package sdtgraph;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.HashMap;


@SuppressWarnings("serial")
public class GaussGraph extends JPanel
{
	public static final Color CORRECT_REJECTIONS_COLOR = Color.GREEN;
	public static final Color MISSES_COLOR = Color.BLUE;
	public static final Color HITS_COLOR = Color.RED;
	public static final Color FALSE_ALARM_COLOR = Color.CYAN;
	
	private double[] randomVariable;
	private double[] probabilityDensityFunction;
	
	//XY Position Caching for PDFs
	private HashMap<Integer, Integer> noiseXYHash = new HashMap<Integer, Integer>();
	private HashMap<Integer, Integer> signalXYHash = new HashMap<Integer, Integer>();
	
	//Internal GUI Constants
	private static int PDF_FACTOR = 5000;
	private static int X_OFFSET = 10, Y_OFFSET = 120;
	private static double X_FACTOR = 2, Y_FACTOR = -1.20;
	
	//Calculated Values for YY,YN,NY,NN
	public static double yyCount = 0;
	public static double ynCount = 0;
	public static double nyCount = 0;
	public static double nnCount = 0;
	
	//Positions of criterion, noise, noise+signal curves
	private int criterionX1, criterionY1, criterionX2, criterionY2;
	private int noiseXAxisXPos = -1, noiseXAxisYPos = -1;
	private int signalXAxisXPos = -1, signalXAxisYPos = -1;
	
	public GaussGraph(int size, double mean, double stdev)
	{		
		randomVariable = new double[size];
		probabilityDensityFunction = new double[size];
		
		for (int i = 0; i < randomVariable.length; i++)
		{
			randomVariable[i] = i;
			probabilityDensityFunction[i] = PDF_FACTOR*Gaussian.phi(i, mean, stdev);
			
			//DEBUG
			//System.out.println("("+i+","+probabilityDensityFunction[i]+")");
		}
	}
	
	@Override
	public void paintComponent(final Graphics g)
	{
		//Draw criterion line
		criterionX1 = (int)(X_FACTOR*6*SDTGraph.getCriterionPosition()+X_OFFSET);
		criterionY1 = 0;
		criterionX2 = (int)(X_FACTOR*6*SDTGraph.getCriterionPosition()+X_OFFSET);
		criterionY2 = (int)((Y_FACTOR*probabilityDensityFunction[probabilityDensityFunction.length-1])+Y_OFFSET*2);
		
		g.setColor(Color.YELLOW);
		g.drawLine( criterionX1 , criterionY1, criterionX2, criterionY2);
		
		//Draw Noise Curve
		drawNoiseCurve(g);
		
		g.setColor(Color.BLACK);
		
		
		//Draw Signal+Noise Curve
		drawSignalNoiseCurve(g);
		
		//Draw False Alarms
		drawFalseAlarms(g);
		
		//Draw Correct Rejections
		drawCorrectRejections(g);
		
		//Draw Misses
		drawMisses(g);
		
		//Draw Hits
		drawHits(g);
	}

	private void drawSignalNoiseCurve(final Graphics g) 
	{
		signalXYHash = new HashMap<Integer, Integer>();
		
		int meanOffset = (int) SDTGraph.signalMeanOffset;
		
		for (int x = 0; x<randomVariable.length-1; x++)
		{			
			int x1 =0, x2 = 0, y1 = 0, y2 = 0;
			
			x1 = (int)((X_FACTOR*randomVariable[x])+X_OFFSET+meanOffset);
			x2 = (int)((X_FACTOR*randomVariable[x+1])+X_OFFSET+meanOffset);
			y1 = (int)((Y_FACTOR*probabilityDensityFunction[x])+Y_OFFSET*2);
			y2 = (int)((Y_FACTOR*probabilityDensityFunction[x+1])+Y_OFFSET*2);
			
			signalXYHash.put(x1, y1);
			signalXYHash.put(x2, y2);
			
			if (x == 0)
			{
				//Draw Y-Axis
				g.setColor(Color.BLACK);
				g.drawLine((int)(x1-meanOffset), 0, (int)(x1-meanOffset), y1);
				
				//Draw Title
				g.setColor(HITS_COLOR);
				g.drawString("Signal+Noise", noiseXAxisXPos+8, noiseXAxisYPos+20);
			}
			else if (x == randomVariable.length-2)
			{
				//Draw X-Axis
				g.setColor(Color.BLACK);
				signalXAxisXPos = (int)((X_FACTOR*randomVariable[0])+X_OFFSET);
				signalXAxisYPos = y2+1;
				g.drawLine(signalXAxisXPos, signalXAxisYPos, Main.X_SIZE, signalXAxisYPos);
			}
			
			g.setColor(HITS_COLOR);
			g.drawLine(x1, y1, x2, y2);
		}
	}

	/**
	 * Draws Noise Gaussian onto Graphics Object
	 * @param g - graphics object to draw curve on
	 */
	private void drawNoiseCurve(Graphics g) 
	{
		noiseXYHash = new HashMap<Integer, Integer>();
		
		int meanOffset = (int) SDTGraph.noiseMeanOffset;
		
		//Draw Noise curve
		for (int x = 0; x<randomVariable.length-1; x++)
		{			
			int x1 =0, x2 = 0, y1 = 0, y2 = 0;
			
			x1 = (int)((X_FACTOR*randomVariable[x])+X_OFFSET+meanOffset);
			x2 = (int)((X_FACTOR*randomVariable[x+1])+X_OFFSET+meanOffset);
			y1 = (int)((Y_FACTOR*probabilityDensityFunction[x])+Y_OFFSET);
			y2 = (int)((Y_FACTOR*probabilityDensityFunction[x+1])+Y_OFFSET);
			
			noiseXYHash.put(x1, y1);
			noiseXYHash.put(x2, y2);
			
			if (x == 0)
			{
				//Draw Y-Axis
				g.setColor(Color.BLACK);
				g.drawLine((int)(x1-meanOffset), 0, (int)(x1-meanOffset), y1);
				
				//Draw Title
				g.setColor(MISSES_COLOR);
				g.drawString("Noise", (int)(x1-meanOffset)+5, 15);
			}
			else if (x == randomVariable.length-2)
			{
				//Draw X-axis
				g.setColor(Color.BLACK);
				noiseXAxisXPos = (int)((X_FACTOR*randomVariable[0])+X_OFFSET);
				noiseXAxisYPos = (int)y2+1;
				g.drawLine( noiseXAxisXPos, noiseXAxisYPos, Main.X_SIZE, noiseXAxisYPos);
			}
			
			g.setColor(MISSES_COLOR);
			g.drawLine( x1, y1, x2, y2 );
		}
	}
	
	/**
	 * Draw Correct Rejections on Signal+Noise Curve
	 * @param g - relevant Graphics object
	 */
	private void drawCorrectRejections(Graphics g) 
	{
		int yIntersect = -1;

		for(Integer x : noiseXYHash.keySet())
		{
			if (x == criterionX1)
			{
				yIntersect = noiseXYHash.get(x);
				break;
			}
		}

		
		if (((Integer)noiseXYHash.keySet().toArray()[0]) < criterionX1 )
		{
			yIntersect = this.noiseXAxisYPos;
		}
		
		
		
		if (yIntersect != -1)
		{
			//Alter NN,NY Count in Table
			//nnCount = 100-(100*((criterionX1+0.0) / (0.0+noisePositionCache.keySet().size())));
			//ynCount = 100 - ynCount;

			if (SDTGraph.showCorrectRejections)
			{
				g.setColor(CORRECT_REJECTIONS_COLOR);
				for(Integer x : noiseXYHash.keySet())
				{
					if (x <= criterionX1)
					{
						g.drawLine(x, noiseXAxisYPos, x, noiseXYHash.get(x));
					}
				}
			}
		}

	}

	/**
	 * Draw Misses on Signal Curve
	 * 
	 * @param g - the Graphics object
	 */
	private void drawMisses(Graphics g) 
	{
		int yIntersect = -1;

		for(Integer x : signalXYHash.keySet())
		{
			if (x == criterionX1)
			{
				yIntersect = signalXYHash.get(x);
				break;
			}
		}

		//Alter YN,YY Count in Table
		//nyCount = 100-(100*((criterionX1+0.0) / (0.0+signalPositionCache.keySet().size())));
		//yyCount = 100 - nyCount;
		
		if (((Integer)signalXYHash.keySet().toArray()[0]) < criterionX1 )
		{
			yIntersect = this.signalXAxisYPos;
		}

		if (yIntersect != -1)
		{			
			if (SDTGraph.showMisses)
			{
				g.setColor(MISSES_COLOR);
				for(Integer x : signalXYHash.keySet())
				{
					if (x <= criterionX1)
					{
						g.drawLine(x, signalXAxisYPos, x, signalXYHash.get(x));
					}
				}
			}
		}
	}

	/**
	 * Highlights Hits on Signal Curve
	 * 
	 * @param g - Relevant Graphics object
	 */
	private void drawHits(Graphics g) 
	{
		int yIntersect = -1;
		
		for(Integer x : signalXYHash.keySet())
		{
			if (x == criterionX1)
			{
				yIntersect = signalXYHash.get(x);
				break;
			}
		}
		
		if (yIntersect == -1)
		{
			int pdfXPos = (Integer)signalXYHash.keySet().toArray()[0];
			
			if (criterionX1 < pdfXPos)
			{
				yyCount = 99;
				nyCount = 1;
				
				if (SDTGraph.showHits)
				{
					g.setColor(HITS_COLOR);
					for(Integer x : signalXYHash.keySet())
					{
						g.drawLine(x, signalXAxisYPos, x, signalXYHash.get(x));
					}
				}
			}
			else
			{
				yyCount = 1;
				nyCount = 99;
			}
			
			return;
		}
		else
		{
			//Alter YY,NY Count in Table
			nyCount = (100*((criterionX1-SDTGraph.signalMeanOffset) / (X_OFFSET+X_FACTOR*signalXYHash.keySet().size())));
			yyCount = 100 - nyCount;

			if (SDTGraph.showHits)
			{
				g.setColor(HITS_COLOR);
				for(Integer x : signalXYHash.keySet())
				{
					if (x >= criterionX1)
					{
						g.drawLine(x, signalXAxisYPos, x, signalXYHash.get(x));
					}
				}
			}
		}
		
	}

	/**
	 * Highlights False Alarms on Signal+Noise Curve
	 * 
	 * @param g - Relevant Graphics object
	 */
	private void drawFalseAlarms(Graphics g) 
	{
		int yIntersect = -1;

		for(Integer x : noiseXYHash.keySet())
		{
			if (x == criterionX1)
			{
				yIntersect = noiseXYHash.get(x);
				break;
			}
		}

		if (yIntersect == -1)
		{
			int pdfXPos = (Integer)noiseXYHash.keySet().toArray()[0];
			
			if (criterionX1 < pdfXPos)
			{
				ynCount = 99;
				nnCount = 1;
				
				if (SDTGraph.showFalseAlarms)
				{
					g.setColor(FALSE_ALARM_COLOR);
					
					for(Integer x : noiseXYHash.keySet())
					{
						g.drawLine(x, noiseXAxisYPos, x, noiseXYHash.get(x));
					}
				}
			}
			else
			{
				ynCount = 1;
				nnCount = 99;
			}
			
			return;
		}
		else
		{
			//Alter NN,NY Count in Table
			nnCount = (100*((criterionX1-SDTGraph.noiseMeanOffset) / (X_OFFSET+X_FACTOR*noiseXYHash.keySet().size())));
			ynCount = 100 - nnCount;

			if (SDTGraph.showFalseAlarms)
			{
				g.setColor(GaussGraph.FALSE_ALARM_COLOR);
				for(Integer x : noiseXYHash.keySet())
				{
					if (x >= criterionX1)
					{
						g.drawLine(x, noiseXAxisYPos, x, noiseXYHash.get(x));
					}
				}
			}
		}
		
	}
}
